/**
 * 
 */

package com.wutianyi.nio.interfaces.impl;

import java.io.IOException;
import java.net.InetSocketAddress;
import java.net.SocketAddress;
import java.nio.channels.ServerSocketChannel;
import java.nio.channels.SocketChannel;
import java.util.ArrayList;
import java.util.Iterator;
import java.util.List;

import org.apache.log4j.Logger;

import com.wutianyi.nio.interfaces.Dispatcher;
import com.wutianyi.nio.interfaces.InputHandlerFactory;

/**
 * @author wutianyi
 * 
 */
public class StandardAcceptor {

	private final Dispatcher			dispatcher;
	private final InputHandlerFactory	inputHandlerFactory;
	private final ServerSocketChannel	listenSocket;
	private final Listener				listener;
	private final List<Thread>			threads	= new ArrayList<Thread>();
	private Logger						logger	= Logger.getLogger(StandardAcceptor.class);
	private volatile boolean			running	= true;

	public StandardAcceptor(ServerSocketChannel listenerSocket, Dispatcher dispatcher,
			InputHandlerFactory inputHandlerFactory) {

		this.listenSocket = listenerSocket;
		this.dispatcher = dispatcher;
		this.inputHandlerFactory = inputHandlerFactory;
		listener = new Listener();
	}

	public StandardAcceptor(SocketAddress socketAddress, Dispatcher dispatcher,
			InputHandlerFactory inputHandlerFactory) throws IOException {

		this(ServerSocketChannel.open(), dispatcher, inputHandlerFactory);
		listenSocket.socket().bind(socketAddress);
	}

	public StandardAcceptor(int port, Dispatcher dispatcher, InputHandlerFactory inputHandlerFactory) throws IOException {

		this(new InetSocketAddress(port), dispatcher, inputHandlerFactory);
	}

	public synchronized Thread newThread() {
		Thread thread = new Thread(listener);
		threads.add(thread);
		thread.start();
		return thread;
	}
	
	/**
	 * 发出通知，并且等待没有现成退出
	 */
	public synchronized void shutdown() {
		running = false;
		for(Iterator<Thread> it = threads.iterator(); it.hasNext();) {
			Thread thread = it.next();
			if((thread != null) && (thread.isAlive())) {
				thread.interrupt();
			}
		}
		for(Iterator<Thread> it = threads.iterator();it.hasNext();) { 
			Thread thread = it.next();
			try {
				thread.join();
			}catch(InterruptedException e) {
				e.printStackTrace();
			}
			it.remove();
		}
		try {
			listenSocket.close();
		}catch(IOException e) {
			// TODO Auto-generated catch block
			e.printStackTrace();
		}
	}
	
	private class Listener implements Runnable {

		/*
		 * (non-Javadoc)
		 * 
		 * @see java.lang.Runnable#run()
		 */
		@Override
		public void run() {
			
			while(running) {
				try {
					SocketChannel client = listenSocket.accept();
					if(null == client) {
						continue;
					}
					dispatcher.registerChannel(client, inputHandlerFactory.newHandler());
					
				}catch(IOException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}catch(IllegalAccessException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}catch(InstantiationException e) {
					// TODO Auto-generated catch block
					e.printStackTrace();
				}
				
			}
		}

	}
}
